////
/// @group helpers/spacing
////

/// Single point spacing
///
/// Returns measurement corresponding to the spacing point requested.
///
/// @param {Number} $spacing-point - Point on the spacing scale
///  (set in `settings/_spacing.scss`)
///
/// @returns {String} Spacing measurement eg. 10px
///
/// @example scss
///   .element {
///     padding: govuk-spacing(5);
///   }
///
/// @example scss Using negative spacing
///   .element {
///     margin-top: govuk-spacing(-1);
///   }
///
/// @example scss Marking spacing declarations as important
///   .element {
///     margin-top: govuk-spacing(1) !important;
///   }
///
/// @access public

@function govuk-spacing($spacing-point) {
  $actual-input-type: type-of($spacing-point);
  @if $actual-input-type != "number" {
    @error "Expected a number (integer), but got a "
      + "#{$actual-input-type}.";
  }

  $is-negative: false;
  @if $spacing-point < 0 {
    $is-negative: true;
    $spacing-point: abs($spacing-point);
  }

  @if not map-has-key($govuk-spacing-points, $spacing-point) {
    @error "Unknown spacing variable `#{$spacing-point}`. Make sure you are using a point from the spacing scale in `_settings/spacing.scss`.";
  }

  $value: map-get($govuk-spacing-points, $spacing-point);
  @return if($is-negative, $value * -1, $value);
}

/// Responsive spacing
///
/// Adds responsive spacing (either padding or margin, depending on `$property`)
/// by fetching a 'spacing map' from the responsive spacing scale, which defines
/// different spacing values at different breakpoints.
///
/// To generate responsive spacing, use 'govuk-responsive-margin' or
/// 'govuk-responsive-padding' mixins
///
/// @param {Number} $responsive-spacing-point - Point on the responsive spacing
///   scale, corresponds to a map of breakpoints and spacing values
/// @param {String} $property - Property to add spacing to (e.g. 'margin')
/// @param {String} $direction [all] - Direction to add spacing to
///   (`top`, `right`, `bottom`, `left`, `all`)
/// @param {Boolean} $important [false] - Whether to mark as `!important`
/// @param {Number} $adjustment [false] - Offset to adjust spacing by
///
/// @access private

@mixin _govuk-responsive-spacing(
  $responsive-spacing-point,
  $property,
  $direction: "all",
  $important: false,
  $adjustment: false
) {
  $actual-input-type: type-of($responsive-spacing-point);
  @if $actual-input-type != "number" {
    @error "Expected a number (integer), but got a " + "#{$actual-input-type}.";
  }

  @if not map-has-key($govuk-spacing-responsive-scale, $responsive-spacing-point) {
    @error "Unknown spacing point `#{$responsive-spacing-point}`. Make sure you are using a point from the "
      + "responsive spacing scale in `_settings/spacing.scss`.";
  }

  // Make sure that the return value from `_settings/spacing.scss` is a map.
  $scale-map: map-get($govuk-spacing-responsive-scale, $responsive-spacing-point);
  $actual-map-type: type-of($scale-map);
  @if $actual-map-type != "map" {
    @error "Expected a number (integer), but got a "
      + "#{$actual-map-type}. Make sure you are using a map to set the responsive spacing in `_settings/spacing.scss`)";
  }

  // Loop through each breakpoint in the map
  @each $breakpoint, $breakpoint-value in $scale-map {
    @if $adjustment {
      $breakpoint-value: $breakpoint-value + $adjustment;
    }

    // The 'null' breakpoint is for mobile.
    @if not $breakpoint {
      @if $direction == all {
        #{$property}: $breakpoint-value if($important, !important, null);
      } @else {
        #{$property}-#{$direction}: $breakpoint-value if($important, !important, null);
      }
    } @else {
      @media #{govuk-from-breakpoint($breakpoint)} {
        @if $direction == all {
          #{$property}: $breakpoint-value if($important, !important, null);
        } @else {
          #{$property}-#{$direction}: $breakpoint-value if($important, !important, null);
        }
      }
    }
  }
}

/// Responsive margin
///
/// Adds responsive margin by fetching a 'spacing map' from the responsive
/// spacing scale, which defines different spacing values at different
/// breakpoints. Wrapper for the `_govuk-responsive-spacing` mixin.
///
/// @see {mixin} _govuk-responsive-spacing
///
/// @param {Number} $responsive-spacing-point - Point on the responsive spacing
/// scale, corresponds to a map of breakpoints and spacing values
/// @param {String} $direction [all] - Direction to add spacing to
///   (`top`, `right`, `bottom`, `left`, `all`)
/// @param {Boolean} $important [false] - Whether to mark as `!important`
/// @param {Number} $adjustment [false] - Offset to adjust spacing by
///
/// @example scss
///   .element {
///      @include govuk-responsive-margin(6, "left", $adjustment: 1px);
///   }
///
/// @access public

@mixin govuk-responsive-margin($responsive-spacing-point, $direction: "all", $important: false, $adjustment: false) {
  @include _govuk-responsive-spacing($responsive-spacing-point, "margin", $direction, $important, $adjustment);
}

/// Responsive padding
///
/// Adds responsive padding by fetching a 'spacing map' from the responsive
/// spacing scale, which defines different spacing values at different
/// breakpoints. Wrapper for the `_govuk-responsive-spacing` mixin.
///
/// @see {mixin} _govuk-responsive-spacing
///
/// @param {Number} $responsive-spacing-point - Point on the responsive spacing
///   scale, corresponds to a map of breakpoints and spacing values
/// @param {String} $direction [all] - Direction to add spacing to
///   (`top`, `right`, `bottom`, `left`, `all`)
/// @param {Boolean} $important [false] - Whether to mark as `!important`
/// @param {Number} $adjustment [false] - Offset to adjust spacing
///
/// @example scss
///   .element {
///      @include govuk-responsive-padding(6, "left", $adjustment: 1px);
///   }
///
/// @access public

@mixin govuk-responsive-padding($responsive-spacing-point, $direction: "all", $important: false, $adjustment: false) {
  @include _govuk-responsive-spacing($responsive-spacing-point, "padding", $direction, $important, $adjustment);
}
